#include "SEHChainView.h"

#include "Bridge.h"

SEHChainView::SEHChainView(StdTable* parent) : StdTable(parent) {
  int charWidth = getCharWidth();

  addColumnAt(8 + charWidth * sizeof(dsint) * 2, tr("Address"),
              true);  // address in the stack
  addColumnAt(8 + charWidth * sizeof(dsint) * 2, tr("Handler"),
              false);  // Exception Handler
  addColumnAt(8 + charWidth * 50, tr("Module/Label"), false);
  addColumnAt(charWidth * 10, tr("Comment"), false);
  connect(Bridge::getBridge(), SIGNAL(updateSEHChain()), this,
          SLOT(updateSEHChain()));
  connect(this, SIGNAL(contextMenuSignal(QPoint)), this,
          SLOT(contextMenuSlot(QPoint)));
  connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
  loadColumnFromConfig("SEH");
  setupContextMenu();
}

void SEHChainView::setupContextMenu() {
  QIcon icon = DIcon(ArchValue("processor32.png", "processor64.png"));
  mFollowAddress = new QAction(icon, tr("Follow &Address"), this);
  connect(mFollowAddress, SIGNAL(triggered()), this, SLOT(followAddress()));
  mFollowHandler = new QAction(icon, tr("Follow Handler"), this);
  mFollowHandler->setShortcutContext(Qt::WidgetShortcut);
  mFollowHandler->setShortcut(QKeySequence("enter"));
  connect(mFollowHandler, SIGNAL(triggered()), this, SLOT(followHandler()));
  connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followHandler()));
}

void SEHChainView::updateSEHChain() {
  DBGSEHCHAIN sehchain;
  memset(&sehchain, 0, sizeof(DBGSEHCHAIN));
  if (!DbgFunctions()->GetSEHChain) return;
  DbgFunctions()->GetSEHChain(&sehchain);
  setRowCount(sehchain.total);
  for (duint i = 0; i < sehchain.total; i++) {
    QString cellText = ToPtrString(sehchain.records[i].addr);
    setCellContent(i, 0, cellText);
    cellText = ToPtrString(sehchain.records[i].handler);
    setCellContent(i, 1, cellText);

    char label[MAX_LABEL_SIZE] = "";
    char module[MAX_MODULE_SIZE] = "";
    DbgGetModuleAt(sehchain.records[i].handler, module);
    QString label_text;
    if (DbgGetLabelAt(sehchain.records[i].handler, SEG_DEFAULT, label))
      label_text = "<" + QString(module) + "." + QString(label) + ">";
    else
      label_text = QString(module);
    setCellContent(i, 2, label_text);
    QString comment;
    if (GetCommentFormat(sehchain.records[i].handler, comment))
      setCellContent(i, 3, comment);
  }
  if (sehchain.total) BridgeFree(sehchain.records);
  reloadData();
}

void SEHChainView::contextMenuSlot(const QPoint pos) {
  if (!DbgIsDebugging() || this->getRowCount() == 0) return;
  QMenu wMenu(this);  // create context menu
  wMenu.addAction(mFollowAddress);
  wMenu.addAction(mFollowHandler);
  QMenu wCopyMenu(tr("&Copy"), this);
  wCopyMenu.setIcon(DIcon("copy.png"));
  setupCopyMenu(&wCopyMenu);
  if (wCopyMenu.actions().length()) {
    wMenu.addSeparator();
    wMenu.addMenu(&wCopyMenu);
  }
  wMenu.exec(mapToGlobal(pos));  // execute context menu
}

void SEHChainView::doubleClickedSlot() { followHandler(); }

void SEHChainView::followAddress() {
  QString addrText = getCellContent(getInitialSelection(), 0);
  DbgCmdExecDirect(QString("sdump " + addrText));
}

void SEHChainView::followHandler() {
  QString addrText = getCellContent(getInitialSelection(), 1);
  DbgCmdExecDirect(QString("disasm " + addrText));
}
